﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Resources;
using System.Collections;
using Qas.User.Properties;
using Qas.CommonLogic;
using Qas.CommonLogic.BusinessObjects;
using Qas.User.Keepers;


namespace Qas.User
{
    /// <summary>
    /// Основная форма графического интерфейса Пользователя (см. Роли)
    /// </summary>
    public partial class FormUser : Form
    {
        /// <summary>
        /// Флаг, показывающий необходимость сохранения
        /// </summary>
        private bool needBeSaved = false;

        /// <summary>
        /// С работающим приложением ассоциируется некоторая база 
        /// (до момента загрузки базы ссылка пуста)
        /// </summary>
        private Base currentBase = null;

        /// <summary>
        ///сначала устанавливаем адрес базы по умолчанию
        /// </summary>
        private String currentPath = Qas.User.Properties.Resources.DefaultBasePath;

        private List<Condition> activePreConditions = new List<Condition>();
        private List<Condition> activePostConditions = new List<Condition>();
        private List<Competence> activeCompetences = new List<Competence>();

        private List<Plan> activeResults = new List<Plan>();

        public FormUser()
        {
            // Стандартная инициализация элементов графического интерфейса
            InitializeComponent();

            string currdir = Environment.CurrentDirectory;
            string[] strarr = currdir.Split(new Char[] { '\\' });

            //string tail = "\\Knowledge\\SimpleBase_1.xml";
            //string tail = "\\Knowledge\\SimpleBase_2.xml";
            //string tail = "\\Knowledge\\simplebase_3.xml";
            //string tail = "\\Knowledge\\SimpleBase_4.xml";
            //string tail = "\\Knowledge\\SimpleBase_5.xml";
            
            //string tail = "\\Knowledge\\SimpleBase_simple.xml";
            //string tail = "\\Knowledge\\SimpleBase_medium.xml";
            string tail = "\\Knowledge\\SimpleBase_large.xml";


            int length = strarr.Length - 3;
            string[] strarrCut = new string[length];

            for (int i = 0; i < length; i++)
            {
                strarrCut[i] = strarr[i];
            }

            string head = string.Join("\\", strarrCut);
            string str = string.Concat(head, tail);

            this.currentBase = LoadBase(str);
            //this.currentBase.ConnectConditions();

            // Заполняем списки пред- и пост- условий, представляемые пользователю
            foreach (Condition condition in this.currentBase.ConditionList)
            {
                this.listBoxPred.Items.Add(condition);
                this.listBoxPost.Items.Add(condition);
            }

            foreach (Competence competence in this.currentBase.AvailableCompetences)
            {
                this.checkedListBoxCompConstraints.Items.Add(competence);
            }

            Log.CreateLog(this.rTextBoxProjLog);
        }

        /// <summary>
        /// Загрузка (десериализация) базы
        /// </summary>
        /// <param name="basePath">Путь к файлу загружаемой базы</param>
        private Base LoadBase(string basePath)
        {
            // Проверяем файл Базы на наличие
            if ((basePath == String.Empty) || (!File.Exists(basePath)))
                throw new NullReferenceException("Файл XML-базы не найден. Путь: " + basePath + "");

            Base result = DataMapper.LoadBaseFromXml(basePath);

            return result;
        }

        private bool SaveBase(string basePath)
        {
            // Проверяем файл Базы на наличие
            if ((basePath == String.Empty) || (!File.Exists(basePath)))
                //throw new NullReferenceException("Файл XML-базы не найден. Путь: " + basePath + "");
                return false;

            DataMapper.SaveBaseToXml(basePath, this.currentBase);

            // Снимаем необходимость сохранения
            this.needBeSaved = false;

            return true;
        }

        /// <summary>
        /// Запуск клиенской части системы - основная процедура
        /// </summary>        
        private void menuItemStart_Click(object sender, EventArgs e)
        {
            // Проверяем, введены ли пред- и постусловия
            if (CheckInput())
            {
                InitAll();

                double availableMoney = double.Parse(this.numCostConst.Value.ToString());

                IKeeper keeper;
                switch (selectALGcombo.SelectedItem.ToString())
                {
                    case "HeurSearch":
                        {
                            keeper = new HeurKeeper(this.currentBase);
                            break;
                        }
                    case "DijkstraSearch":
                        {
                            keeper = new KeeperDijkstra(this.currentBase);
                            break;
                        }
                    default:
                        {
                            keeper = new BasicK(this.currentBase);
                            BasicK.flagALG = selectALGcombo.SelectedItem.ToString();
                            break;
                        }
                }

                // Фильтруем множество задач
                List<Task> tasksForActiveCompetences = keeper.FilterByCompetences(
                     this.activeCompetences, this.currentBase.AvailableTasks);

                List<Plan> resultOfWorking = keeper.Search(tasksForActiveCompetences,
                    this.activePreConditions, this.activePostConditions);

                // Вывод результата
                if (StepForwardResultsExist(resultOfWorking))
                {
                    foreach (Plan res in resultOfWorking)
                    {
                        this.listBoxPlans.Items.Add(res);
                        this.activeResults.Add(res);
                    }
                }
            }
        }



        private void OpnFileMenuItem_Click(object sender, EventArgs e)
        {
            if (this.needBeSaved)
            {
                SaveBase(this.currentPath);
            }

            this.opnFileDialog = new OpenFileDialog();

            this.opnFileDialog.InitialDirectory = "C:\\Qas\\Knowledge";
            this.opnFileDialog.Filter = "(*.xml)|*.xml|All files (*.*)|*.*";
            this.opnFileDialog.FilterIndex = 1;
            this.opnFileDialog.RestoreDirectory = true;

            if (this.opnFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    if ((this.opnFileDialog.OpenFile()) != null)
                    {
                        // Загрузка базы
                        this.currentPath = this.opnFileDialog.FileName;
                        this.currentBase = LoadBase(this.currentPath);

                        // Очищаем и заполняем списки пред- и пост- условий, представляемые пользователю
                        this.ClearCurrentLists();

                        // Снимаем блокировки списков условий
                        this.UnLockConditionLists();

                        foreach (Condition condition in this.currentBase.ConditionList)
                        {
                            this.listBoxPred.Items.Add(condition);
                            this.listBoxPost.Items.Add(condition);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

        }

        /// <summary>
        /// Блокировка элементов управления - списков условие
        /// </summary>
        private void LockConditionLists()
        {
            this.listBoxPred.Enabled = false;
            this.listBoxPost.Enabled = false;
        }

        /// <summary>
        /// Снятие блокировок элементов управления - списков условие
        /// </summary>
        private void UnLockConditionLists()
        {
            this.listBoxPred.Enabled = true;
            this.listBoxPost.Enabled = true;
        }

        // Очистка элементов управления и рабочих списков
        private void ClearCurrentLists()
        {
            this.activePostConditions.Clear();
            this.activePreConditions.Clear();
            this.listBoxPred.Items.Clear();
            this.listBoxPost.Items.Clear();
            this.listBoxTasks.Items.Clear();
            this.listBoxPlans.Items.Clear();

            this.lblCostVal.Text = String.Empty;
            this.lblTimeVal.Text = String.Empty;
            this.panelPlanInfo.Text = String.Empty;
            this.rTextBoxProjLog.Text = string.Empty;
            this.numCostConst.Value = 0;
            this.numTimeConst.Value = 0;
            this.checkedListBoxCompConstraints.SelectedItems.Clear();
        }

        //Корректировка списка планов в сответствии с завершенными задачами
        //Удаление лишних планов
        private void deletePlan(Task task)
        {
            Plan selectedResult = this.listBoxPlans.SelectedItem as Plan;
            int selectedTaskIndex = this.listBoxTasks.SelectedIndex;

            foreach (Plan res in this.activeResults)
            {
                if ((res.Tasks.IndexOf(task) != selectedTaskIndex) && (res != selectedResult))
                {
                    this.listBoxPlans.Items.Remove(res);
                }
            }
        }

        //Восстановление планов
        private void restorePlan(Task task)
        {
            Plan selectedResult = this.listBoxPlans.SelectedItem as Plan;
            int selectedTaskIndex = this.listBoxTasks.SelectedIndex;

            foreach (Plan res in this.activeResults)
            {
                if ((res.Tasks.IndexOf(task) != selectedTaskIndex) && (!this.listBoxPlans.Items.Contains(res as Plan)))
                {
                    this.listBoxPlans.Items.Add(res);
                }
            }
        }

        private void listBoxPlans_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Чистим список задач
            this.ClearTasks();

            // Выделяем активный план

            Plan activePlan = this.listBoxPlans.SelectedItem as Plan;
            if (activePlan == null)
            {
                // Чистим поля                
                this.panelPlanInfo.Text = string.Empty;
                this.lblCostVal.Text = string.Empty;
                this.lblTimeVal.Text = string.Empty;

                return;
            }
            //else
            //{
            // Добавляем задачи в список задач
            foreach (Task task in activePlan.Tasks)
            {
                if (!this.listBoxTasks.Items.Contains(task as Task))
                {
                    this.listBoxTasks.Items.Add(task);
                }
            }

            // Меняем заголовок
            this.panelPlanInfo.Text = activePlan.Title;

            // Рассчитываем стоимость и ориентировочное время
            this.lblCostVal.Text = activePlan.Cost.ToString();
            this.lblTimeVal.Text = activePlan.ExpectancyTime.ToString();

            //}
        }

        /// <summary>
        /// Удаление из списка задая, которые не помечены выполенными
        /// </summary>
        private void ClearTasks()
        {
            if (this.listBoxTasks.Items.Count > 0)
            {
                if (this.listBoxTasks.GetItemChecked(0) == false)
                {
                    this.listBoxTasks.Items.Clear();
                    return;
                }
                else
                {
                    // сохранение выполненных задач
                    List<Task> notCompletedTasks = new List<Task>();
                    foreach (Task task in this.listBoxTasks.Items)
                    {
                        if (!this.listBoxTasks.CheckedItems.Contains(task))
                            notCompletedTasks.Add(task);
                    }

                    foreach (Task task in notCompletedTasks)
                    {
                        this.listBoxTasks.Items.Remove(task as Task);
                    }
                }
            }
        }

        private void ItemCheckHandler(object sender, ItemCheckEventArgs e)
        {
            // Необходимо сохранить
            this.needBeSaved = true;

            // Проверить, отмечены ли предыдущие задачи
            CheckedListBox clb = sender as CheckedListBox;
            if (clb == null)
                throw new NullReferenceException();

            switch (e.CurrentValue)
            {
                case CheckState.Unchecked:
                    {
                        int index = clb.SelectedIndex;

                        if (index > 0)
                        {
                            for (int i = index - 1; index >= 0; index--)
                            {

                                if (clb.GetItemCheckState(i) != CheckState.Checked)
                                {
                                    e.NewValue = CheckState.Unchecked;
                                    return;
                                }

                            }
                        }
                        // вызов формы для ввода фактической характеристики задачи

                        ExpertForm Form = new ExpertForm(clb.SelectedItem as Task);
                        switch (Form.ShowDialog())
                        {
                            case DialogResult.OK:
                                {
                                    this.needBeSaved = true;
                                    break;
                                }
                            default:
                                {
                                    e.NewValue = CheckState.Unchecked;
                                    break;
                                }
                        }

                        // Удаление из списка плана, который неактуален после выбора задачи
                        this.deletePlan(clb.SelectedItem as Task);

                        break;
                    }
                case CheckState.Checked:
                    {
                        int index = clb.SelectedIndex;

                        if (index < clb.Items.Count - 1)
                        {
                            for (int i = index + 1; index < clb.Items.Count; index++)
                            {

                                if (clb.GetItemCheckState(i) != CheckState.Unchecked)
                                {
                                    e.NewValue = CheckState.Checked;
                                    return;
                                }

                            }
                        }

                        //Восстановление списка планов после отмены задачи
                        this.restorePlan(clb.SelectedItem as Task);
                        break;
                    }
                case CheckState.Indeterminate:
                    {
                        return;
                    }
            }
        }

        /// <summary>
        /// Проверка задания начальных условий и целей проекта
        /// </summary>
        private bool CheckInput()
        {
            if ((listBoxPost.CheckedItems.Count == 0) ||
                //(listBoxPred.CheckedItems.Count == 0) || (допускаем отсутствие предусловий)
                (checkedListBoxCompConstraints.CheckedItems.Count == 0) ||
                (double.Parse(numCostConst.Value.ToString()) == 0) ||
                (double.Parse(numTimeConst.Value.ToString()) == 0) || (selectALGcombo.SelectedItem == null))
            {
                MessageBox.Show("Проверьте начальные условия");
                return false;
            }

            return true;
        }

        private void FormClosingHandler(object sender, FormClosingEventArgs e)
        {
            if (this.needBeSaved)
            {
                SaveBase(Qas.User.Properties.Resources.DefaultBasePath);
            }
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            if (this.needBeSaved)
            {
                SaveBase(this.currentPath);
            }
            this.Close();
            this.Dispose();
        }

        private void FormUser_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Инициализация всех списков условий
        /// </summary>
        private void InitAll()
        {
            // Чистим списки
            activePostConditions.Clear();
            activePreConditions.Clear();
            activeCompetences.Clear();
            listBoxPlans.Items.Clear();
            rTextBoxProjLog.Clear();

            // Смотрим, какие задачи выбирал пользователь
            foreach (Condition cond in this.listBoxPred.CheckedItems)
            {
                this.activePreConditions.Add(cond);
            }

            foreach (Condition cond in this.listBoxPost.CheckedItems)
            {
                this.activePostConditions.Add(cond);
            }

            foreach (Competence competence in this.checkedListBoxCompConstraints.CheckedItems)
            {
                this.activeCompetences.Add(competence);
            }
        }

        /// <summary>
        /// Проверяет существование результатов в множестве планов
        /// </summary>
        private bool StepForwardResultsExist(List<Plan> resultToCheck)
        {
            if (resultToCheck.Count == 0)
            {
                rTextBoxProjLog.Text = "При заданных условиях целей достичь невозможно\n";
                Log.WriteToLog(activePreConditions, 1);
                Log.WriteToLog(activePostConditions, 0);
                return false;
            }

            return true;
        }

        private void btnSelectAllCompetences_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < this.checkedListBoxCompConstraints.Items.Count; i++)
            {
                this.checkedListBoxCompConstraints.SetItemChecked(i, true);
            }

        }
    }
}
